﻿
using System.Runtime.InteropServices;
//https://www.cnblogs.com/xiashengwang/archive/2012/08/01/2618286.html
Console.WriteLine("MemoryPressureDemo size=0");
MemoryPressureDemo(0);//0导致垃圾回收器不频发

Console.WriteLine("MemoryPressureDemo size=" + (10 * 1024 * 1024));
MemoryPressureDemo(10 * 1024 * 1024);//10M 导致频繁的垃圾回收

HandeCollectorDemo();

MemoryRequestDemo();

new GCMehtod().GCMehtodDemo();//演示GC的相关方法
/*这个类用于预测需求大量内存的操作能否成功，个人感觉很有用。它构造函数的参数是需要的内存量，单位是Mb。
 * 如果需要的内存不能请求成功，会抛出一个InsufficientMemoryException异常，
 * 这个异常继承自OutOfMemoryException异常，可以通过捕捉它来进行判断。
*/

void MemoryRequestDemo()
{
    try
    {
        //逻辑上保留1.5G 的空间
        using (System.Runtime.MemoryFailPoint mfp = new System.Runtime.MemoryFailPoint(1500))
        {
            //在这里执行内存消耗大的算法

        }//Dispose方法逻辑上释放这1.5G内存
    }
    catch (InsufficientMemoryException e)
    {
        //无法保留所需的内存
        Console.WriteLine(e);
    }
}



/*
 HandleCollector
   这个也是用于本地资源的类。主要用于本地资源数量有限，如果长时间无效而未得到垃圾清理可能会导致请求失败。
这个类有计数器的功能，当超过给定的初始值时，垃圾回收器就强制执行垃圾回收。
 */
void HandeCollectorDemo()
{
    Console.WriteLine("HandeCollectorDemo");
    for (var i = 0; i < 10; i++)
    {
        new LimitedResource();
    }
    //出于演示，强制垃圾回收
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
/*
    这两个方法主要用于本地资源，比如一个位图占用了50M本地内存，
但是托管对象只包含一个HBitMap（4字节或8字节）。但CRL并不知道这个内存压力，
它可能允许你分配数百个位图，因为它们占用的托管内存太少了。
这两个方法的目的就是要告诉GC它实际的本地资源用了多少内存量，
GC知道这个信息后会调整它的垃圾回收策略，当压力变大时，他就强制执行垃圾回收。*/
void MemoryPressureDemo(int size)
{
    //创建一组对象，并指定它们的逻辑大小
    for (var i = 0; i < 15; i++)
    {
        new BigNativeResource(size);
    }
    //为了演示，强制回收前面的这一组对象
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

sealed class BigNativeResource
{
    private int m_size;
    public BigNativeResource(int size)
    {
        m_size = size;
        if (m_size > 0)
        {
            GC.AddMemoryPressure(size);//让垃圾回收器认为对象在物理上比较大

        }
        Console.WriteLine("BigNativeResource create");
    }

    ~BigNativeResource()
    {
        if (m_size > 0)
        {
            GC.RemoveMemoryPressure(m_size);//让垃圾回收器认为释放了更多的内存

        }
        Console.WriteLine("BigNativeResource destroy");
    }
}


 sealed class LimitedResource
{
    //创建一个HandleCollector，告诉它有2个或更多的这样的对象存在于堆中，就执行垃圾回收
    private static HandleCollector s_hc = new HandleCollector("LimitedResource", 2);

    public LimitedResource()
    {
        s_hc.Add();//告诉HandleCollector，堆中又增加了一个LimitedResource对象
        Console.WriteLine("LimitedResource create. Count={0}", s_hc.Count);
    }

    ~LimitedResource()
    {
        s_hc.Remove();//告诉HandleCollector，已经从堆中移除了一个LimitedResource对象
        Console.WriteLine("LimitedResource destroy. Count={0}", s_hc.Count);
    }
}



/*
 
 public static void Collect(); //回收全部
public static void Collect(int generation);//回收指定的代
public static void Collect(int generation, GCCollectionMode mode)//回收指定的代，Mode一般应选择Optimized
public enum GCCollectionMode

{

        Default = 0,   //目前和Forced等效，强制回收

        Forced = 1,    //强制回收

        Optimized = 2,//只有能释放大量内存或能减少碎片化的前提下，才执行回收

}

public static void WaitForPendingFinalizers();//挂起调用线程，直到freachable情况，完成对每个对象的Finalize方法调用。
我们经常可能看到如下代码：

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
这三句的作用是：强制回收，等待Finalize执行完毕，再次强制回收（因为Finalize的那些对象只有下次垃圾回收才真正回收，所以这里要再调一次）

RegisterForFullGCNotification，WaitForFullGCApproach，WaitForFullGCComplete，CancelFullGCNotification这几个方法是关于垃圾回收通知的，一般情况下，用的较少，可以参见MSDN的专题：http://technet.microsoft.com/zh-cn/library/cc713687.aspx
public static int GetGeneration(object obj); //获取对象的代
public static int GetGeneration(WeakReference wo);//获取一个弱引用对象的代
public static long GetTotalMemory(bool forceFullCollection);//获取托管应用程序的内存大小
public static void KeepAlive(object obj);//保持对象不被垃圾回收直到单前代码
public static int CollectionCount(int generation);//进程启动后，取得特定代上执行的垃圾回收次数
5，另外值得关注的几个类
GCHandle：可用于手动监视对象的生命期。
WeakReference：它实际是GCHandle的一个包装类，使用它时无需特权，它是弱引用，所有不支持GCHandleType的Normal或Pinned值。
SafeHandle，SafeFileHandle，SafeWaitHandle，SafeBuffer，SafeRegistryHandle。
        其中SafeHandle是其它几个类的抽象基类。它们主要用于与非托管代码进行安全的互操作。
 */

class Genobj
{
    ~Genobj()
    {
        Console.WriteLine("In Finalize Mehtod.");
    }
}
public class GCMehtod()
{
  public  void GCMehtodDemo()
    {
        Console.WriteLine("MaxGeneration={0}", GC.MaxGeneration);
        Genobj o = new Genobj();

        Console.WriteLine("o in Gen " + GC.GetGeneration(o));//0

        //force collecton
        GC.Collect();
        Console.WriteLine("o in Gen " + GC.GetGeneration(o));//1

        GC.Collect();
        Console.WriteLine("o in Gen " + GC.GetGeneration(o));//2

        o = null;//

        Console.WriteLine("collecting gen 0");
        GC.Collect(0);
        GC.WaitForPendingFinalizers();

        Console.WriteLine("collecting gen 1");
        GC.Collect(1);
        GC.WaitForPendingFinalizers();

        Console.WriteLine("collecting gen 2");
        GC.Collect(2);
        GC.WaitForPendingFinalizers();
    }
}